package serie10;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.File;
import java.io.IOException;
import java.util.Observable;
import java.util.Observer;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;

public class Splitter {
	
	// ATTRIBUTS
	
	private static final int  NB_ITEM_MAX = 100;
	
	private static final int CONST = 1000; 
	
	private static final int LENGTH_TEXT = 25;
	
	private static final int LENGTH_PATH = 15;
	
	private JFrame frame;
	
	private SplitManager model;
	
	private JButton parcourir;
	
	private JButton fragmenter;
	
	private JTextField chemin;
	
	private JTextField octet;
	
	private JComboBox nbFragments;
	
	private JTextArea texte;
	
	private JFileChooser fc;
	
	private JScrollPane jsp;
	
	private Observer obs;
	
	private ActionListener al;
	
	// CONSTRUCTEURS
	
	public Splitter() {
        createView();
        placeComponents();
        createController();
	}
	
	// COMMANDES

    /**
     * Rend l'application visible au centre de l'�cran.
     */
    public void display() {
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
    
    // OUTILS
    
    private void createModel(File f) {
    	model = new StdSplitManager(f);
    	model.addObserver(obs);
    	model.notifyObservers();
    }
    
    private void createView() {
        frame = new JFrame("Fragmenteur de fichiers");
        parcourir = new JButton("Parcourir...");
        fragmenter = new JButton("Fragmenter");
        chemin = new JTextField(LENGTH_PATH);
        octet = new JTextField(4);
        nbFragments = new JComboBox();
        texte = new JTextArea(10, LENGTH_TEXT);
        jsp = new JScrollPane(texte);
        fc = new JFileChooser();
        fragmenter.setEnabled(false);
        octet.setEnabled(false);
        nbFragments.setEnabled(false);
        al = new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int i = (Integer) nbFragments.getSelectedItem();
				model.setSplitsNumber(i); 
			}
    	};
        obs = new Observer() {
			public void update(Observable arg0, Object arg1) {
				// obs est un observateur qui r�initialise l'application
				nbFragments.removeActionListener(al);
				nbFragments.removeAllItems();
				int nbItems = (int) (model.getFileSize() / CONST + 1);
				int number = (int) Math.min(nbItems, NB_ITEM_MAX);
				for (int i = 1; i <= number; i++) {
            		nbFragments.addItem(i);
            	}
				octet.setEnabled(true);
		        nbFragments.setEnabled(true);
				texte.setText("");
				octet.setText("");
				nbFragments.addActionListener(al);
				model.deleteObserver(this);
				model.addObserver(new Observer() {
		            public void update(Observable o, Object arg) {
		            	// 2e observateur
		            	if (model.getFileSize() == 0) {
		            		fragmenter.setEnabled(false);
		            	} else {
		            		texte.setText("");
		            		fragmenter.setEnabled(true); 
		            		texte.append("Taille totale du fichier : " 
		            					+ model.getFileSize() + " octets\n\n" 
		            					+ "Description des fragments du "
		            					+ "fichier :\n");
		    				int tabLength = model.getSplitsNames().length;
		    				for (int i = 0; i < tabLength; i++) {
		    					texte.append("  " + model.getSplitsNames()[i] 
		    					            + " " + model.getSplitsSizes()[i] 
		    							    + " octets\n");
		    				}
		    				int averageLength;
		    				int accu = 0;
		    				for (int i = 0; i < tabLength; i++) {
		    					accu += model.getSplitsSizes()[i];
		    				}
		    				averageLength = accu / tabLength;
		    				texte.append("\nTaille moyenne d'un fragment : " 
		    								+ averageLength + "octets");
		            	}
		            	
		            }
				});
			}
        };
    }
    
    private void placeComponents() {
    	frame.setLayout(new FlowLayout());
    	JPanel p = new JPanel(new BorderLayout()); {
    		JPanel q = new JPanel(); {
    			q.add(new JLabel("Fichier � fragmenter"));
    			q.add(chemin);
    			q.add(parcourir);
    		}
    		p.add(q, BorderLayout.NORTH);
    		q = new JPanel(new GridLayout(0, 2)); {
    			JPanel j = new JPanel(); {
    				JPanel t = new JPanel(new GridLayout(3, 1)); {
    					JPanel r = new JPanel(); {
    						r.add(new JLabel("Nb. fragments:"));
    						r.add(nbFragments);
    					}
    					t.add(r);
    					r = new JPanel(); {
    						r.add(new JLabel("Taille des fragments:*"));
    						r.add(octet);
    						r.add(new JLabel("octets"));
    					}
    					t.add(r);
    					r = new JPanel(); {
    						r.add(fragmenter);
    					}
    					t.add(r);
    				}
    				j.add(t, BorderLayout.NORTH);
    				j.setBorder(BorderFactory.createEtchedBorder());
    			}
        		q.add(j);
        		q.setBorder(BorderFactory.createEtchedBorder());
        		q.add(jsp);
    		}
    		p.add(q, BorderLayout.CENTER);
    		q = new JPanel(); {
    			q.add(new JLabel("(*)Il s'agit de la taille de chaque " 
    					+ "fragment � un octet pr�s, sauf peut �tre pour le " 
    					+ "dernier fragment."
    			));
    		}
    		p.add(q, BorderLayout.SOUTH);
    	}
    	frame.add(p);
    }
    
    private void createController() {
    	frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    	
    	parcourir.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				int choice = fc.showOpenDialog(null);
				if (choice == JFileChooser.APPROVE_OPTION) {
					File f = fc.getSelectedFile();
					if (f.exists() && f.canRead()) {
						String file = f.getAbsolutePath();
						chemin.setText(file); 
						createModel(new File(file));
					} else {
						JOptionPane.showMessageDialog(
								null, 
								"Mauvais fichier !!!", 
								"Erreur", 
								JOptionPane.ERROR_MESSAGE
						);
					}
				} 
			}
    	});
    	
    	chemin.addKeyListener(new KeyListener() {
			public void keyTyped(KeyEvent e) {
				if (e.getKeyChar() == KeyEvent.VK_ENTER) {
					File file = new File(chemin.getText());
					if (file.exists() && file.canRead()) {
						createModel(file); 
					} else {
						JOptionPane.showMessageDialog(
								null, 
								"Fichier inexistant ou impossible � lire !!!", 
								"Erreur", 
								JOptionPane.ERROR_MESSAGE
						);
						chemin.setText("");
					}
				}
			}
			public void keyPressed(KeyEvent arg0) { }
			public void keyReleased(KeyEvent arg0) { }
    	});
    	
    	nbFragments.addActionListener(al);
    	
    	octet.addKeyListener(new KeyListener() {
			public void keyTyped(KeyEvent e) {
				if (e.getKeyChar() == KeyEvent.VK_ENTER) {
					try {
						if (Integer.decode(octet.getText()) >= CONST) {
							model.setSplitsSizes(Long.decode(octet.getText()));
						} else {
							JOptionPane.showMessageDialog(
									null, 
									"Taille des fragments inf�rieure "
									+ "� 1000 !!!", 
									"Erreur", 
									JOptionPane.ERROR_MESSAGE
							);
							octet.setText("");
						}
					} catch (NumberFormatException e1) {
						JOptionPane.showMessageDialog(
								null, 
								"Vous devez donner un nombre pour la taille"
								+ " des fragments", 
								"Erreur", 
								JOptionPane.ERROR_MESSAGE
						);
						octet.setText("");
					}
				}
			}
			public void keyPressed(KeyEvent arg0) { }
			public void keyReleased(KeyEvent arg0) { }
    	});
    	
    	fragmenter.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				try {
					model.split();
					JOptionPane.showMessageDialog(
							null, 
							"Concassion r�ussie !!!", 
							"Gagn�", 
							JOptionPane.INFORMATION_MESSAGE
					);
				} catch (IOException e1) {
					JOptionPane.showMessageDialog(
							null, 
							"Concassion impossible !!!", 
							"Erreur", 
							JOptionPane.ERROR_MESSAGE
					);
				}
				
			}
    	});
    }
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Splitter().display();
            }
        });
    }

}
